home *** CD-ROM | disk | FTP | other *** search
/ Aminet 24 / Aminet 24 (1998)(GTI - Schatztruhe)[!][Apr 1998].iso / Aminet / comm / mail / Mutt089src.lha / Mutt-0.89i-AMIGA / src / buffy.c < prev    next >
C/C++ Source or Header  |  1998-01-28  |  9KB  |  410 lines

  1. /* 
  2.  * Copyright (C) 1996-8 Michael R. Elkins <me@cs.hmc.edu>
  3.  * 
  4.  *     This program is free software; you can redistribute it and/or modify
  5.  *     it under the terms of the GNU General Public License as published by
  6.  *     the Free Software Foundation; either version 2 of the License, or
  7.  *     (at your option) any later version.
  8.  * 
  9.  *     This program is distributed in the hope that it will be useful,
  10.  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  *     GNU General Public License for more details.
  13.  * 
  14.  *     You should have received a copy of the GNU General Public License
  15.  *     along with this program; if not, write to the Free Software
  16.  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  */
  18.  
  19. #include "mutt.h"
  20. #include "buffy.h"
  21. #include "mx.h"
  22. #include "mailbox.h"
  23.  
  24. #include <string.h>
  25. #include <sys/stat.h>
  26. #include <dirent.h>
  27. #include <utime.h>
  28. #include <ctype.h>
  29.  
  30. #include <stdio.h>
  31.  
  32. static time_t BuffyTime = 0;    /* last time we checked for new mail */
  33. static short BuffyCount = 0;    /* how many boxes with new mail */
  34. static short BuffyNotify = 0;    /* # of unnotified new boxes */
  35.  
  36. #ifdef BUFFY_SIZE
  37.  
  38. #include "parse.h"
  39.  
  40. /* Find the last message in the file. * upon success return 0. * If no
  41.  * message found - return -1 */
  42. int fseek_last_message (FILE * f)
  43. {
  44.   long int pos;
  45.   char buffer[BUFSIZ + 7];    /* 7 for "\n\nFrom " */
  46.   int bytes_read;
  47.   int i;            /* Index into `buffer' for scanning.  */
  48.   memset (buffer, 0, BUFSIZ+7);
  49.   fseek (f, 0, SEEK_END);
  50.   pos = ftell (f);
  51.  
  52.   /* Set `bytes_read' to the size of the last, probably partial, buffer; 0 <
  53.    * `bytes_read' <= `BUFSIZ'.  */
  54.   bytes_read = pos % BUFSIZ;
  55.   if (bytes_read == 0)
  56.     bytes_read = BUFSIZ;
  57.   /* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all
  58.    * reads will be on block boundaries, which might increase efficiency.  */
  59.   while ((pos -= bytes_read) >= 0)
  60.   {
  61.     /* we save in the buffer at the end the first 7 chars from the last read */
  62.     strncpy (buffer + BUFSIZ, buffer, 7);
  63.     fseek (f, pos, SEEK_SET);
  64.     bytes_read = fread (buffer, sizeof (char), bytes_read, f);
  65.     if (bytes_read == -1)
  66.       return -1;
  67.     for (i = bytes_read; --i >= 0;)
  68.       if (!strncmp (buffer + i, "\n\nFrom ", strlen ("\n\nFrom ")))
  69.       {                /* found it - go to the beginning of the From */
  70.     fseek (f, pos + i + 2, SEEK_SET);
  71.     return 0;
  72.       }
  73.     bytes_read = BUFSIZ;
  74.   }
  75.  
  76.   /* here we are at the beginning of the file */
  77.   if (!strncmp ("From ", buffer, 5))
  78.   {
  79.     fseek (f, 0, 0);
  80.     return (0);
  81.   }
  82.  
  83.   return (-1);
  84. }
  85.  
  86. /* Return 1 if the last message is new */
  87. int test_last_status_new (FILE * f)
  88. {
  89.   HEADER *hdr;
  90.   int result = 0;
  91.  
  92.   if (fseek_last_message (f) == -1)
  93.     return (0);
  94.  
  95.   hdr = mutt_new_header ();
  96.   mutt_read_rfc822_header (f, hdr);
  97.   if (!(hdr->read || hdr->old))
  98.     result = 1;
  99.   mutt_free_header (&hdr);
  100.  
  101.   return result;
  102. }
  103.  
  104. int test_new_folder (const char *path)
  105. {
  106.   FILE *f;
  107.   int rc = 0;
  108.   int typ;
  109.  
  110.   typ = mx_get_magic (path);
  111.  
  112.   if (typ != M_MBOX && typ != M_MMDF)
  113.     return 0;
  114.  
  115.   f = fopen (path, "rb");
  116.   rc = test_last_status_new (f);
  117.   fclose (f);
  118.  
  119.   return rc;
  120. }
  121.  
  122. BUFFY *mutt_find_mailbox (const char *path)
  123. {
  124.   BUFFY *tmp = NULL;
  125.   struct stat sb;
  126.   struct stat tmp_sb;
  127.   
  128.   if (stat (path,&sb) != 0)
  129.     return NULL;
  130.  
  131.   for (tmp = Incoming; tmp; tmp = tmp->next)
  132.   {
  133.     if (stat (tmp->path,&tmp_sb) ==0 && 
  134.     sb.st_dev == tmp_sb.st_dev && sb.st_ino == tmp_sb.st_ino)
  135.       break;
  136.   }
  137.   return tmp;
  138. }
  139.  
  140. void mutt_update_mailbox (BUFFY * b)
  141. {
  142.   struct stat sb;
  143.  
  144.   if (!b)
  145.     return;
  146.  
  147.   if (stat (b->path, &sb) == 0)
  148.     b->size = (long) sb.st_size;
  149.   else
  150.     b->size = 0;
  151.   return;
  152. }
  153. #endif
  154.  
  155. int mutt_parse_mailboxes (const char *s, void *data, char *err, size_t errlen)
  156. {
  157.   BUFFY **tmp;
  158.   char buf[_POSIX_PATH_MAX];
  159.   char expn[LONG_STRING];
  160. #ifdef BUFFY_SIZE
  161.   struct stat sb;
  162. #endif /* BUFFY_SIZE */
  163.  
  164.   do
  165.   {
  166.     s = mutt_extract_token (buf, sizeof (buf), s, expn, sizeof (expn), 0);
  167.     mutt_expand_path (buf, sizeof (buf));
  168.     /* simple check to avoid duplicates */
  169.     for (tmp = &Incoming; *tmp; tmp = &((*tmp)->next))
  170.     {
  171.       if (strcmp (buf, (*tmp)->path) == 0)
  172.     break;
  173.     }
  174.  
  175.     if (!*tmp)
  176.     {
  177.       *tmp = (BUFFY *) safe_calloc (1, sizeof (BUFFY));
  178.       (*tmp)->path = safe_strdup (buf);
  179.       (*tmp)->next = NULL;
  180.     }
  181.  
  182.     (*tmp)->new = 0;
  183.     (*tmp)->notified = 1;
  184.     (*tmp)->newly_created = 0;
  185.  
  186. #ifdef BUFFY_SIZE
  187.     /* for buffy_size, it is important that if the folder is new (tested by
  188.      * reading it), the size is set to 0 so that later when we check we see
  189.      * that it increased .  without buffy_size we probably don't care.
  190.      */
  191.     if (stat ((*tmp)->path, &sb) == 0 && !test_new_folder ((*tmp)->path))
  192.     {
  193.       /* some systems out there don't have an off_t type */
  194.       (*tmp)->size = (long) sb.st_size;
  195.     }
  196.     else
  197.       (*tmp)->size = 0;
  198. #endif /* BUFFY_SIZE */
  199.   }
  200.   while (s);
  201.   return 0;
  202. }
  203.  
  204. #ifdef BUFFY_SIZE
  205. /* people use buffy_size on systems where modified time attributes are BADLY
  206.  * broken. Ignore them.
  207.  */
  208. #define STAT_CHECK (sb.st_size > tmp->size)
  209. #else
  210. #define STAT_CHECK (sb.st_mtime > sb.st_atime || (tmp->newly_created && sb.st_ctime == sb.st_mtime && sb.st_ctime == sb.st_atime))
  211. #endif /* BUFFY_SIZE */
  212.  
  213. int mutt_buffy_check (void)
  214. {
  215.   BUFFY *tmp;
  216.   struct stat sb;
  217.   time_t t;
  218.   struct dirent *de;
  219.   DIR *dirp;
  220.   char path[_POSIX_PATH_MAX];
  221.   struct stat contex_sb;
  222.  
  223.   /* fastest return if there are no mailboxes */
  224.   if (!Incoming)
  225.     return 0;
  226.   t = time (NULL);
  227.   if ((t - BuffyTime) < BuffyTimeout)
  228.     return BuffyCount;
  229.   BuffyTime = t;
  230.   BuffyCount = 0;
  231.   BuffyNotify = 0;
  232.  
  233.   /* check device ID and serial number instead of comparing paths */
  234.   if (!Context || !Context->path || stat (Context->path, &contex_sb) != 0)
  235.   {
  236.     contex_sb.st_dev=0;
  237.     contex_sb.st_ino=0;
  238.   }
  239.   
  240.   for (tmp = Incoming; tmp; tmp = tmp->next)
  241.   {
  242.     tmp->new = 0;
  243.  
  244.     if (stat (tmp->path, &sb) != 0 ||
  245.     (!tmp->magic && (tmp->magic = mx_get_magic (tmp->path)) <= 0))
  246.     {
  247.       /* if the mailbox still doesn't exist, set the newly created flag to
  248.        * be ready for when it does.
  249.        */
  250.       tmp->newly_created = 1;
  251.       tmp->magic = 0;
  252. #ifdef BUFFY_SIZE
  253.       tmp->size = 0;
  254. #endif
  255.       continue;
  256.     }
  257.  
  258.     if (!Context || !Context->path || 
  259.     sb.st_dev != contex_sb.st_dev || sb.st_ino != contex_sb.st_ino)
  260.     {
  261.       switch (tmp->magic)
  262.       {
  263.       case M_MBOX:
  264.       case M_MMDF:
  265.  
  266.     if (STAT_CHECK)
  267.     {
  268.       BuffyCount++;
  269.       tmp->new = 1;
  270.     }
  271. #ifdef BUFFY_SIZE
  272.     else
  273.     {
  274.       /* some other program has deleted mail from the folder */
  275.       tmp->size = (long) sb.st_size;
  276.     }
  277. #endif
  278.     if (tmp->newly_created &&
  279.         (sb.st_ctime != sb.st_mtime || sb.st_ctime != sb.st_atime))
  280.       tmp->newly_created = 0;
  281.  
  282.     break;
  283.  
  284.       case M_MAILDIR:
  285.  
  286.     snprintf (path, sizeof (path), "%s/new", tmp->path);
  287.     if ((dirp = opendir (path)) == NULL)
  288.     {
  289.       tmp->magic = 0;
  290.       break;
  291.     }
  292.     while ((de = readdir (dirp)) != NULL)
  293.     {
  294.       if (*de->d_name != '.')
  295.       {
  296.         /* one new message is enough */
  297.         BuffyCount++;
  298.         tmp->new = 1;
  299.         break;
  300.       }
  301.     }
  302.     closedir (dirp);
  303.     break;
  304.  
  305.       case M_MH:
  306.  
  307.     if ((dirp = opendir (tmp->path)) == NULL)
  308.     {
  309.       tmp->magic = 0;
  310.       break;
  311.     }
  312.     while ((de = readdir (dirp)) != NULL)
  313.     {
  314.       if (!mh_valid_message (de->d_name))
  315.         continue;
  316.       snprintf (path, sizeof (path), "%s/%s", tmp->path, de->d_name);
  317.       if (stat (path, &sb) != -1 && sb.st_mtime > sb.st_atime)
  318.       {
  319.         BuffyCount++;
  320.         tmp->new = 1;
  321.         break;
  322.       }
  323.     }
  324.     closedir (dirp);
  325.     break;
  326.       }
  327.     }
  328. #ifdef BUFFY_SIZE
  329.     else if (Context && Context->path)
  330.       tmp->size = (long) sb.st_size;    /* update the size */
  331. #endif
  332.  
  333.     if (!tmp->new)
  334.       tmp->notified = 0;
  335.     else if (!tmp->notified)
  336.       BuffyNotify++;
  337.   }
  338.   return (BuffyCount);
  339. }
  340.  
  341. void mutt_buffy_notify (void)
  342. {
  343.   BUFFY *tmp;
  344.   char path[_POSIX_PATH_MAX];
  345.  
  346.   if (mutt_buffy_check () && BuffyNotify)
  347.   {
  348.     for (tmp = Incoming; tmp; tmp = tmp->next)
  349.     {
  350.       if (tmp->new && !tmp->notified)
  351.       {
  352.     strfcpy (path, tmp->path, sizeof (path));
  353.     mutt_pretty_mailbox (path);
  354.     mutt_message ("New mail in %s.", path);
  355.     tmp->notifie